﻿//  Author:
//       Daniel Großer <olav.daniel.grosser@googlemail.com>
//  
//  Copyright (c) 2012 Copyright (C) 2012 by Daniel Großer. This Code is under GNU LGPL 3.0
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
// 
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Beauty;
using Beauty.Tools;

namespace Beauty.Test
{
    /// <summary>
    /// This class contains tests for all classes of Beauty in case everything runs fine.
    /// These test cases check whether Beauty works fine if its input is fine.
    /// </summary>
    [TestFixture]
    public class Core
    {
        /// <summary>
        /// Test the NamespaceLanguageProvider and AssemblyLanguageProvider classes.
        /// </summary>
        [Test]
        public void LanguageProviders()
        {
            var namespaceProvider = new NamespaceLanguageProvider(GetType().Assembly, "Beauty.Test.Languages.Language1");
            Assert.AreEqual(11, namespaceProvider.AbstractSyntaxTreeNodes.Count(), "NamespaceLanguageProvider works incorrectly.");

            var assemblyProvider = new AssemblyLanguageProvider(GetType().Assembly);
            Assert.AreEqual(47, assemblyProvider.AbstractSyntaxTreeNodes.Count(), "AssemblyLanguageProvider works incorrectly.");
        }

        /// <summary>
        /// This test tests the processing of terminals and the concatenation pattern.
        /// So:
        /// A ::= "terminal"
        /// A ::= B C D
        /// </summary>
        [Test]
        public void Terminals()
        {
            var parser = new Parser(new NamespaceLanguageProvider(GetType().Assembly, "Beauty.Test.Languages.Language1"));

            parser.Parse<Languages.Language1.KeywordNode>("keyword");
            parser.Parse<Languages.Language1.DelimeterNode>(".");
            parser.Parse<Languages.Language1.RegexNode>("123");

            var result = parser.Parse<Languages.Language1.DifferentTerminals>("keyword keyword KeYwOrD keyword keyword 123 keyword.identifier");
            Assert.IsNull(result.Keyword_Ignored, "Ignored terminals should not get assigned!");
            Assert.AreEqual("keyword", result.Keyword_NotIgnored, "Not ignored terminals should be assigned!");
            Assert.AreEqual("KeYwOrD", result.Keyword_NotIgnoredCaseSensitive, "Case-insensitivity should be available.");
            Assert.AreEqual("keyword", result.Keyword_CustomData.Data, "Custom token data type failed!");
            Assert.AreEqual("keyword", result.Keyword_PredefinedData.TokenText, "Token class not constructed correctly.");
            Assert.AreEqual(1u, result.Keyword_PredefinedData.LineStart, "Token class not constructed correctly.");
            Assert.AreEqual(1u, result.Keyword_PredefinedData.LineEnd, "Token class not constructed correctly.");
            Assert.AreEqual(33u, result.Keyword_PredefinedData.ColumnStart, "Token class not constructed correctly.");
            Assert.AreEqual(41u, result.Keyword_PredefinedData.ColumnEnd, "Token class not constructed correctly.");

            Assert.AreEqual(123, result.RegEx_IConvertible, "IConvertible failed!");
        }

        /// <summary>
        /// Test BNF optional pattern.
        /// A ::= B? C
        /// </summary>
        [Test]
        public void BNF_Optional()
        {
            var parser = new Parser(new NamespaceLanguageProvider(GetType().Assembly, "Beauty.Test.Languages.Language1"));

            parser.Parse<Languages.Language1.Block>("declare\nbegin\nend");
            parser.Parse<Languages.Language1.Block>("\nbegin\nend");
        }

        /// <summary>
        /// Test BNF repetition pattern.
        /// A ::= {B}
        /// </summary>
        [Test]
        public void BNF_Repetition()
        {
            var parser = new Parser(new NamespaceLanguageProvider(GetType().Assembly, "Beauty.Test.Languages.Language1"));
            var result = parser.Parse<Languages.Language1.Sets>("{1}[{}] {1 2} {1 2 3} {1 2 3 4} {1 2 3 4 5}");

            Assert.AreEqual(1, result.Numbers1a.Length, "Arrays are not read correctly.");
            Assert.IsNull(result.Numbers1b, "Optional arrays are not read correctly.");
            Assert.AreEqual(2, result.Numbers2.Count(), "IEnumerables are not processed correctly.");
            Assert.AreEqual(3, result.Numbers3.Count(), "Lists are not processed correctly.");
            Assert.AreEqual(4, result.Numbers4.Count(), "Custom lists are not read correctly.");
            Assert.AreEqual(5, result.Numbers5.Count(), "Custom readonly lists are not read correctly.");
        }

        /// <summary>
        /// Test BNF alternation pattern.
        /// A ::= B | C
        /// </summary>
        [Test]
        public void BNF_Alternation()
        {
            var parser = new Parser(new NamespaceLanguageProvider(GetType().Assembly, "Beauty.Test.Languages.Language1"));
            var result = parser.Parse<Languages.Language1.Alternation>("begin.");
            Assert.IsTrue(result.FirstEntity is Languages.Language1.BeginKeyword);
            result = parser.Parse<Languages.Language1.Alternation>("end.");
            Assert.IsTrue(result.FirstEntity is Languages.Language1.EndKeyword);
        }
		
		/// <summary>
		/// Tests the functioning of the DependsOn property.
		/// </summary>
		[Test]
		public void TestDependsOn()
		{
            var parser = new Parser(new NamespaceLanguageProvider(GetType().Assembly, "Beauty.Test.Languages.Language9"));
            var result = parser.Parse<Languages.Language9.YesNo>("YES");
			Assert.AreEqual("YES", result.ToString());
            result = parser.Parse<Languages.Language9.YesNo>("NO");
			Assert.AreEqual("NO", result.ToString());			
		}

        /// <summary>
        /// Test the BNF example
        /// </summary>
        [Test]
        public void BNF()
        {
            var parser = new Parser(new NamespaceLanguageProvider(GetType().Assembly, "Beauty.Test.Languages.BNF"));
            parser.Parse<Languages.BNF.BNF>("<S> ::= <A> | <B><C>.\n<A> ::= \"A\" | \"a\". \n<B> ::= \"B\" | \"b\". \n<C> ::= \"C\" | \"c\".");
        }
		
		/// <summary>
		/// Simple the simple language example.
		/// </summary>
		[Test]
		public void Simple()
		{
            var parser = new Parser(new NamespaceLanguageProvider(GetType().Assembly, "Beauty.Test.Languages.SimpleLanguage"));
            parser.Parse<Languages.SimpleLanguage.Block>(@"
				var
 					i : int;
 					s : string;
				begin
 					i := 0;
 					i := i + 3;
				end");
		}
    }
}
